#!/bin/zsh

### Generate the Zsh script to load a plugin.
#
# usage: antidote script [-h|--help] [-k|--kind <kind>] [-p|--path <path>]
#                        [-c|--conditional <func>] [-b|--branch <branch>]
#                        [--pre <func>] [--post <func>] [--skip-load-defer]
#                        [-a|--autoload <path>] <bundle>
# <kind>   : zsh,path,fpath,defer,clone,autoload
# <path>   : Relative path from the bundle root
# <branch> : The git branch
# <bundle> : A bundle can be a directory, a zsh script, or a git repo
#

### Generate the Zsh script to load a plugin.
#function antidote-script {
  emulate -L zsh; setopt local_options $_adote_funcopts
  local MATCH MBEGIN MEND; local -a match mbegin mend  # appease 'warn_create_global'
  local REPLY=

  local -a o_help o_kind o_path o_branch o_cond o_autoload o_pre o_post o_fpath_rule o_skip_load_defer
  zparseopts $_adote_zparopt_flags -- \
    h=o_help       -help=h            \
    a:=o_autoload  -autoload:=a       \
    b:=o_branch    -branch:=b         \
    k:=o_kind      -kind:=k           \
    p:=o_path      -path:=p           \
                   -pre:=o_pre        \
                   -post:=o_post      \
                   -fpath-rule:=o_fpath_rule \
                   -skip-load-defer=o_skip_load_defer \
    c:=o_cond      -conditional:=c    ||
    return 1

  # set defaults
  (( $#o_kind )) || o_kind=(--kind zsh)
  if ! (( $#o_fpath_rule )); then
    zstyle -a ':antidote:fpath' rule 'o_fpath_rule' || o_fpath_rule=(append)
  fi

  # strip '=' or ':' from beginning of arg values
  local re='^[=:]?(.+)$'
  [[ $o_kind[-1] =~ $re ]] && o_kind[-1]=$match
  [[ $o_autoload[-1] =~ $re ]] && o_autoload[-1]=$match
  [[ $o_path[-1] =~ $re ]] && o_path[-1]=$match
  [[ $o_cond[-1] =~ $re ]] && o_cond[-1]=$match
  [[ $o_branch[-1] =~ $re ]] && o_branch[-1]=$match
  [[ $o_pre[-1] =~ $re ]] && o_pre[-1]=$match
  [[ $o_post[-1] =~ $re ]] && o_post[-1]=$match
  [[ $o_fpath_rule[-1] =~ $re ]] && o_fpath_rule[-1]=$match

  local supported_kind_vals=(autoload clone defer fpath path zsh)
  if (( $#o_kind )) && ! (( $supported_kind_vals[(Ie)$o_kind[-1]] )); then
    print -ru2 "antidote: error: unexpected kind value: '$o_kind[-1]'" && return 1
  fi

  # If no fpath_rule is set, use the zstyle
  if ! (( $#o_fpath_rule )); then
    local zstyle_fpath_rule
    zstyle -s ':antidote:fpath' rule 'zstyle_fpath_rule'
    [[ -z "$zstyle_fpath_rule" ]] || o_fpath_rule=($zstyle_fpath_rule)
  fi

  local supported_fpath_rules=(append prepend)
  if ! (( $supported_fpath_rules[(Ie)$o_fpath_rule[-1]] )); then
    print -ru2 "antidote: error: unexpected fpath rule: '$o_fpath_rule[-1]'" && return 1
  fi

  local bundle=$1
  if [[ -z "$bundle" ]]; then
    print -ru2 "antidote: error: bundle argument expected" && return 1
  fi
  local bundle_name=$(__antidote_bundle_name $bundle)

  # replace ~/ with $HOME/
  if [[ "$bundle" == '~/'* ]]; then
    bundle=$HOME/${bundle#'~/'*}
  fi

  # set the path to the bundle (repo or local)
  local bundle_path
  [[ -e "$bundle" ]] && bundle_path=$bundle || bundle_path=$(__antidote_bundle_dir $bundle)

  # handle cloning repo bundles
  local bundle_type
  bundle_type="$(__antidote_bundle_type $bundle)"
  if [[ "$bundle_type" == (repo|url|sshurl) ]] && [[ ! -e "$bundle_path" ]]; then
    local giturl=$(__antidote_tourl $bundle)
    print -ru2 "# antidote cloning $bundle_name..."
    git clone --quiet --recurse-submodules --shallow-submodules $o_branch $giturl $bundle_path
    [[ $? -eq 0 ]] || return 1
  fi

  # if we only needed to clone the bundle, compile and we're done
  if [[ "$o_kind[-1]" == "clone" ]]; then
    if zstyle -t ":antidote:bundle:$bundle" zcompile; then
      __antidote_bundle_zcompile $bundle_path
    fi
    return
  fi

  # add path to bundle
  [[ -n "$o_path[-1]" ]] && bundle_path+="/$o_path[-1]"

  # handle defer pre-reqs first
  local dopts zsh_defer='zsh-defer'
  zstyle -s ":antidote:bundle:${bundle}" defer-options 'dopts'
  [[ -n "$dopts" ]] && zsh_defer="zsh-defer $dopts"

  # generate the script
  local -a script=()

  # add pre-load function
  (( $#o_pre )) && script+=("$o_pre[-1]")

  # handle defers
  local source_cmd="source"
  local zsh_defer_bundle
  zstyle -s ':antidote:defer' bundle 'zsh_defer_bundle' \
    || zsh_defer_bundle='romkatv/zsh-defer'
  if [[ "$o_kind[-1]" == "defer" ]]; then
    source_cmd="${zsh_defer} source"
    if ! (( $#o_skip_load_defer )); then
      script+=(
        'if ! (( $+functions[zsh-defer] )); then'
        "$(antidote-script $zsh_defer_bundle | __antidote_indent)"
        'fi'
      )
    fi
  fi

  # Let's make the path a little nicer to deal with
  local print_bundle_path="$(__antidote_print_path "$bundle_path")"

  # handle autoloading before sourcing
  if (( $#o_autoload )); then
    if [[ "$o_fpath_rule[-1]" == prepend ]]; then
      script+=("fpath=( \"${print_bundle_path}/${o_autoload[-1]}\" \$fpath )")
      script+=("builtin autoload -Uz \$fpath[1]/*(N.:t)")
    else
      script+=("fpath+=( \"${print_bundle_path}/${o_autoload[-1]}\" )")
      script+=("builtin autoload -Uz \$fpath[-1]/*(N.:t)")
    fi
  fi

  # generate load script
  bundle_type="$(__antidote_bundle_type $bundle_path)"
  local fpath_script
  if [[ "$o_fpath_rule[-1]" == prepend ]]; then
    fpath_script="fpath=( \"$print_bundle_path\" \$fpath )"
  else
    fpath_script="fpath+=( \"$print_bundle_path\" )"
  fi

  if [[ "$o_kind[-1]" == fpath ]]; then
    # fpath
    script+="$fpath_script"
  elif [[ "$o_kind[-1]" == path ]]; then
    # path
    script+="export PATH=\"$print_bundle_path:\$PATH\""
  elif [[ "$o_kind[-1]" == autoload ]]; then
    # autoload
    script+=("$fpath_script")
    if [[ "$o_fpath_rule[-1]" == prepend ]]; then
      script+=("builtin autoload -Uz \$fpath[1]/*(N.:t)")
    else
      script+=("builtin autoload -Uz \$fpath[-1]/*(N.:t)")
    fi
  else
    if zstyle -t ":antidote:bundle:$bundle" zcompile; then
      __antidote_bundle_zcompile $bundle_path
    fi
    if [[ $bundle_type == file ]]; then
      script+="$source_cmd \"$print_bundle_path\""
    else
      # directory/default
      local initfile initfiles
      initfiles=(${(@f)$(__antidote_initfiles $bundle_path)})
      # if no init file was found, assume the default
      if [[ $#initfiles -eq 0 ]]; then
        if (( $#o_path )); then
          initfiles=($bundle_path/${bundle_path:t}.plugin.zsh)
        else
          initfiles=($bundle_path/${bundle_name:t}.plugin.zsh)
        fi
      fi
      script+="$fpath_script"
      local print_initfile
      for initfile in $initfiles; do
        print_initfile="$(__antidote_print_path "$initfile")"
        script+="$source_cmd \"$print_initfile\""
      done
    fi
  fi

  # add post-load function
  if (( $#o_post )); then
    if [[ "$o_kind[-1]" == "defer" ]]; then
      script+=("${zsh_defer} $o_post[-1]")
    else
      script+=("$o_post[-1]")
    fi
  fi

  # mark bundle as loaded
  # script+="zstyle ':antidote:bundle:${bundle_name}' loaded yes"

  # wrap conditional
  if [[ -n "$o_cond[-1]" ]]; then
    print "if $o_cond[-1]; then"
    printf "  %s\n" $script
    print "fi"
  else
    printf "%s\n" $script
  fi
#}
